package com.lin.blog.service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import com.google.appengine.api.datastore.AsyncDatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Transaction;
import com.lin.blog.entity.BaseBean;

public abstract class AbstractService<T extends BaseBean> {
	private AsyncDatastoreService datastoreService = DatastoreServiceFactory
			.getAsyncDatastoreService();

	@SuppressWarnings("unchecked")
	public T get(Long id) throws Exception {
		Key key = KeyFactory.createKey(getShortName(), id);
		Entity entity = datastoreService.get(key).get();
		Map<String, Object> values = entity.getProperties();
		return (T) map2Bean(values).setId(entity.getKey().getId());
	}

	@SuppressWarnings("unchecked")
	protected T map2Bean(Map<String, Object> values) {
		T obj = (T) BeanUtils.instantiateClass(getGenricType());
		BeanWrapper wrapper = new BeanWrapperImpl(obj);
		wrapper.setPropertyValues(values);
		return obj;
	}

	public void update(T obj) {
		try {
			Entity entity = tTEntity(obj);
			datastoreService.put(entity);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	public void save(T obj) {
		Transaction tx = datastoreService.getCurrentTransaction();
		try {
			long id = IDService.getInstance(datastoreService).getIdByType(
					obj.getShortName()) + 1;
			obj.setId(id);
			Entity entity = tTEntity(obj);
			datastoreService.put(entity);
			IDService.getInstance(datastoreService).update(obj.getShortName(),
					id);
			tx.commitAsync();
		} catch (Exception e) {
			tx.rollbackAsync();
		}

	}

	public void delete(T obj) {
		datastoreService.delete(KeyFactory.createKey(getShortName(),
				obj.getId()));
	}

	public void delete(List<T> objs) {
		List<Key> keys = new ArrayList<Key>(objs.size());
		for (T obj : objs) {
			keys.add(obj.getKey());
		}
		datastoreService.delete(keys);
	}

	public Object query() {
		return null;
	}

	protected Entity tTEntity(T obj) throws IllegalArgumentException,
			IllegalAccessException {
		Entity entity = new Entity(getShortName(), obj.getId());
		for (Field field : getGenricType().getDeclaredFields()) {
			field.setAccessible(true);
			entity.setProperty(field.getName(), field.get(obj));
		}
		return entity;
	}

	@SuppressWarnings("rawtypes")
	public abstract Class getGenricType();

	public abstract String getShortName();

}
